#pragma once
#include <skia/core/SkGraphics.h>
#include <skia/core/SkCanvas.h>
#include <skia/core/SkSurface.h>
#include <skia/core/SkData.h>
#include <skia/core/SkImage.h>
#include <skia/core/SkImageInfo.h>
#include <skia/encode/SkPngEncoder.h>
#include <skia/core/SkPath.h>
#include <skia/codec/SkEncodedImageFormat.h>
#include <skia/core/SkStream.h>
#include <skia/core/SkMatrix.h>
#include <skia/core/SkPaint.h>
#include <skia/core/SkBitmap.h>
#include <skia/core/SkColorSpace.h>
#include <skia/core/SkColorFilter.h>
#include <skia/effects/SkColorMatrix.h>

#include <iostream>
#include <filesystem>
#include <string>
#include <fstream>
#include <sstream>
#include <cxxopts.hpp>

sk_sp<SkImage> createBitmapFromData(const void* data, size_t length) {
	auto skData = SkData::MakeWithCopy(data, length);
	return SkImages::DeferredFromEncodedData(skData);
}
sk_sp<SkImage> LoadFromFile(const char* _path) {
	std::ifstream _ifs(_path, std::ios::binary);
	_ifs.seekg(0, std::ios::end);
	size_t _fsz = (size_t)_ifs.tellg();
	_ifs.seekg(0, std::ios::beg);
	std::vector<char> _bytes;
	_bytes.resize(_fsz);
	_ifs.read(&_bytes[0], (std::streamsize)_fsz);
	_ifs.close();

	return createBitmapFromData(&_bytes[0], _bytes.size());
}
/**
 * 使用示例：
 * .\build\Release\hello --file=test.png
 * .\build\Release\hello --file test.png --width 750 --height 940
 */
int main(int argc, char** argv) {
    cxxopts::Options options("hello", "this is usage of skia demo");
    options.add_options()
        ("w,width", "Image Width", cxxopts::value<int>()->default_value("750"))
        ("h,height", "Image Height", cxxopts::value<int>()->default_value("940"))
        ("f,file", "File name", cxxopts::value<std::string>())
        // ("v,verbose", "Verbose output", cxxopts::value<bool>()->default_value("false"))
    ;

    auto result = options.parse(argc, argv);
    int width = 750, height = 940;
    std::string file = "";
    if(result.count("width") || result.count("height")){
        width = result["width"].as<int>();
        height = result["height"].as<int>();
        std::cout << "Image Width: " << result["width"].as<int>() << " Image Height: " << result["height"].as<int>() << std::endl;
    }
    if(result.count("file")){
        file = result["file"].as<std::string>();
        std::cout << "File path: " << result["file"].as<std::string>() << std::endl;
    } else {
        std::cerr << "Please input file path" << std::endl;
        return 0;
    }
    //初始化skia
    SkGraphics::Init();
    auto info = SkImageInfo::MakeN32Premul(width, height);
	auto surface = SkSurfaces::Raster(info);
    SkSamplingOptions samplingOptions = SkSamplingOptions(SkFilterMode::kLinear, SkMipmapMode::kLinear);
    if (!surface) {
		throw std::runtime_error("Failed to create surface");
	}
	auto canvas = surface->getCanvas();
	if (!canvas) {
		throw std::runtime_error("Failed to get canvas from surface");
	}
	auto paint = std::make_unique<SkPaint>();
	paint->setAntiAlias(true);
	paint->setBlendMode(SkBlendMode::kSrcOver);
    //填充黑色背景
    canvas->clear(SK_ColorBLACK);
    SkColorMatrix colorMatrix(
		// Red channel
		0, 0, 0, 0, 1,  // M11, M21, M31, M41, M51 (M51 goes here as the offset)
		// Green channel
		0, 0, 0, 0, 1,  // M12, M22, M32, M42, M52 (M52 goes here as the offset)
		// Blue channel
		0, 0, 0, 0, 1,  // M13, M23, M33, M43, M53 (M53 goes here as the offset)
		// Alpha channel
		0, 0, 0, 1, 0   // M14, M24, M34, M44, M54 (M54 goes here as the offset)
	);
	auto colorFilter = SkColorFilters::Matrix(colorMatrix);
	// paint = std::make_unique<SkPaint>();
    //设置颜色矩阵
	paint->setColorFilter(colorFilter);
	//加载图片
    auto image = LoadFromFile(file.c_str());//"H:/cmake-learn/test.png"
    if (!image) {
        throw std::runtime_error("Failed to load image");
    }
    //绘制图片
    canvas->drawImage(image, 0, 0, samplingOptions, paint.get());
    //保存绘制结果为png图片
    auto bitmap = surface->makeImageSnapshot();
	auto buffer = SkPngEncoder::Encode(nullptr, bitmap.get(), SkPngEncoder::Options());
	if (!buffer) {
		throw std::runtime_error("Failed to encode image to data");
	}
	const char* fileName = "out.png";//std::string (dirPath / (std::to_string(_frame) + ".png")).string();
	SkFILEWStream stream(fileName);//.c_str()
	if (!stream.write(buffer->data(), buffer->size())) {
		throw std::runtime_error("Failed to write image data to file");
	}
	stream.flush();
    std::cout << "Image convert successfully and saved to " << fileName << std::endl;
    // std::cin.get();
    return 0;
}